/*
 *  cpu_gui/MainWindow.cpp
 *  
 *              CPU Monitor 
 *
 *    Spring Semester.  044800.    Technion.
 *   Copyright (C) 2006  Evgeny Shulman  and Elizabeth Shtrom 
 */

#include <stdio.h>
#include <stdlib.h>

#include <linux/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>





#include "../cpu_common.h"
#include "../cpu_console/cpu_console.h"

#ifdef  QT_TOOLS_INSTALLED
	#include <QApplication>
	#include <QPlastiqueStyle>
	#include "tabdialog.h"
#endif

int silent = 0;
int fd[8];
int nrCPUs =1;


int show_cpuid = 0;
int	show_regs = 0;
int	show_idt = 0;
int	show_gdt = 0;
int	show_ldt = 0;
int	show_tss =0;
int	show_pgd  =0;
int	show_pt  =0;
int	show_im  =0;

int show_from  = 0;
int show_count = 0;
int show_repeat =10;
int show_cpu = -1;
int show_pt_entry = -2;
int is_console=0;

int run_on = -1;


int init_fd (int *_fd);
int close_fd(int *_fd);

int run_console(void );
static int parse_command_line (int argc, char **argv);
void usage (char *programname);




int main(int argc, char *argv[])
 {
     int ret;
     cpu_set_t affinityModeDefault;
    if ( parse_command_line (argc, argv) ) {
		fprintf( stderr, "Error on parsing..\n" );
    	return -1;
    }
   
    if (  init_fd(fd)  ) {
		fprintf( stderr, "Failed to open cpu driver\n" );
		return -1;
    }
     
    
    if (  ( run_on >=0 )   && ( run_on < nrCPUs ) ) {
    	CPU_ZERO(&affinityModeDefault);
		CPU_SET( run_on, &affinityModeDefault);
		PDEBUG("cpu_set_affinity:cpu %d \n", run_on);
		if ( sched_setaffinity(0, sizeof(affinityModeDefault), &affinityModeDefault) < 0) {
   			fprintf(stderr,"cpu_set_affiniti:sched_setaffinity error.");
   			goto cpu_main_out;
   		}
  	}else {
  		if (sched_getaffinity(0, sizeof(affinityModeDefault), &affinityModeDefault) < 0) {
			fprintf(stderr,"sched_getaffinity error");
			goto cpu_main_out;
		}
	}
    if (is_console){
     	ret = run_console();
    }else{


#ifdef QT_TOOLS_INSTALLED
		 QApplication app(argc, argv);
     	 QApplication::setStyle(new QPlastiqueStyle);
	
	     MyWidget widget(nrCPUs,affinityModeDefault);
	     widget.show();
	     ret=app.exec();
#else
		ret  = -1;
		fprintf( stderr, "No QT tools preinstalled on the system.\n Please use -h for getting help \n" );
#endif	
	
	}
cpu_main_out:	
     close_fd(fd);
     return ret;
 }

int init_fd(int *_fd){
	nrCPUs = sysconf (_SC_NPROCESSORS_CONF);
	char cpuname[20];
	
	if (!silent) {
		printf ("Found %u CPU \n", nrCPUs);
		if (nrCPUs > 1)
			printf ("s");
		
		if ((nrCPUs < 1) || (nrCPUs > 8)) {
			printf("CPU count is bogus: defaulting to 1 CPU.\n");
			nrCPUs = 1;
		}
	}
	
	for( int i=0; i< nrCPUs; i++){
		snprintf (cpuname,19, "/dev/cpu_monitor%d", i);
		_fd[i] = open (cpuname,O_RDWR);
		if (_fd[i] < 0){
			fprintf(stderr, "\n%s failed to open, fd=%d\n",cpuname,_fd[i]);
			return -1;
		}
		PDEBUG ("init_fd : cpu %d is opened \n ", i );
	}
	return 0;
}




int close_fd(int *_fd){
	for( int i=0; i< nrCPUs; i++){
		PDEBUG ("init_fd : cpu  _fd[%d]=  %d is closed\n ",  i, _fd[i] );
		close(_fd[i] ) ;
	}
	return 0;
}


void usage (char *programname)
{
	printf ("\n\
Usage: \n\
    %s [<switches>]\n\
\n\
Example:\n\
========\n\
	%s -idt -from 15 -count 10      ( will display idt entries from 15 to 25 )\n\
\n\
Switches:\n\
========\n\
    -a,   --all               -display all\n\
    -c,   --cpuid             -display cpuid data ( including cache data)\n\
    -g,   --gdt               -display gdt\n\
    -i,   --idt               -display idt\n\
    -t,   --tss               -display tss\n\
    -r,   --registers         -display regs\n\
    -p,   --pgd               -display pgd table\n\
    -pt                       -display pt table\n\
    -im   --monitor           -display idt + start interrupts monitor for 10 secundes + displays stats each second \n\
    \n\
    \n\
    -from                     -index  of entry to start from\n\
    -count                    -number of entries to display      \n\
    -repeat                   -number of seconds to run interrupt manager \n\
    -pgt_entry                -number of entry in pgd to show the page table for \n\
    \n\
    -cpu                      -id of CPU to display ( otherwise all CPUs will be processed\n\
    -run_on                   -id of CPU to run on  (default affinity mask  )\n\
    \n\
    -h  ? --help              -display this screen       \n\
\n\
                CPU Monitor \n\
 \n\
        Spring Semester.  044800.    Technion.\n\
     Copyright (C) 2006  Evgeny Shulman  and Elizabeth Shtrom \n\
\n\
\n", programname,programname);
	
	
	exit (0);
}   
    
static int parse_command_line (int argc, char **argv)
{   
	char **argp, *arg;
	int 	*get_number_target;
	int get_number = 0;
	for (argp = argv+1; argp <= argv + argc && (arg = *argp); argp++) {
		
		if ( get_number) {
			*get_number_target = atoi ( arg);
			get_number = 0 ;
		}
		
		if ((!strcmp(arg, "-a") || !strcmp(arg, "--all"))) {
			show_cpuid = 1;
			show_regs = 1;
			show_idt = 1;
			show_gdt = 1;
			show_ldt = 1;
			show_tss =1;
			show_pt = 1;
			show_im  =1;
		}


		if ((!strcmp(arg, "-id") || !strcmp(arg, "--cpuid"))) {
			show_cpuid = 1;
		}


		if ((!strcmp(arg, "-r") || !strcmp(arg, "--registers")))
			show_regs = 1;

		if ((!strcmp(arg, "-i") || !strcmp(arg, "--idt")))
			show_idt = 1;

		if ((!strcmp(arg, "-g") || !strcmp(arg, "--gdt")))
			show_gdt = 1;

		if ((!strcmp(arg, "-l") || !strcmp(arg, "--ldt")))
			show_ldt = 1;

		if ((!strcmp(arg, "-t") || !strcmp(arg, "--tss")))
			show_tss = 1;

		if ((!strcmp(arg, "-p") || !strcmp(arg, "--pgd")))
			show_pgd = 1;
		
		if ((!strcmp(arg, "-pt") || !strcmp(arg, "--pt")))
		{
			PDEBUG("FFFF\n\n\n" );
				show_pt = 1;
		}
		
		if ((!strcmp(arg, "-im") || !strcmp(arg, "--monitor")))
			show_im = 1;
		
			
			
		if ((!strcmp(arg, "?") || !strcmp(arg, "--help")))
			usage(argv[0]);	
		if (!strcmp(arg, "-run_on")) {
			get_number =1;
			get_number_target = &run_on;
		}
		
		if ( !strcmp(arg, "-from") ){
			get_number = 1;
			get_number_target = &show_from;
		}
		if ( !strcmp(arg, "-count") ){
			get_number = 1;
			get_number_target = &show_count;
		}
		if ( !strcmp(arg, "-repeat") ){
			get_number = 1;
			get_number_target = &show_repeat;
		}
		if ( !strcmp(arg, "-pgt_entry") ){
			get_number = 1;
			get_number_target = &show_pt_entry;
		}
		if ( !strcmp(arg, "-cpu") ){
			get_number = 1;
			get_number_target = &show_cpu;
		}
						
	}
	if ( get_number ) {
		fprintf( stderr, "wrong use of -from / -count /-cpu /-repeat /-show_pt_entry switches! \n" );
		return -1;
	}
	is_console = is_console || show_cpuid || show_regs || show_idt || show_gdt || show_ldt || show_tss;
	is_console = is_console || show_pgd   || show_pt   ||show_im ;
	
//	if ( is_console && !is_cpu ){
//		fprintf( stderr, "Cpu num not speciefied!  use -c <num>  or --cpu <num> switch\n" );
//		return -1;
//	}
	
	
	
	PDEBUG ( "from %d \n" , show_from);
	return 0;
	
}

int run_console(void ){
	int  cpu;
	int from, count = 10;
	
	
	
	from = show_from  ;
	if( show_count ) 
		count = show_count;
	
	for( cpu=0; cpu< nrCPUs; cpu++){
		if (  ( show_cpu >=0 ) && ( show_cpu != cpu )  ) 
			continue;
		
		if ( show_cpuid ) {
			check_cpuid(fd[cpu]);
		}
		
		if ( show_regs ) {
			check_regs(fd[cpu]);	
		}
		
		
		if ( show_idt ) {
			check_idt (fd[cpu],from,count);
		}
		
		if ( show_gdt ) {
			check_gdt (fd[cpu],from,count);
		}
		
		if ( show_tss ) {
			check_tss(fd[cpu] );
		}
		if ( show_ldt ) {
			check_ldt (fd[cpu], from,count);
		}
		
		
		if ( show_pgd ) {
			check_pgd_and_pt ( fd[cpu], from,count,-1);
		}
		if ( show_pt ) {
			check_pgd_and_pt ( fd[cpu], from,count, show_pt_entry);
		}
	
	}	
	
	if ( show_im  ){
		check_im_smp ( fd, nrCPUs, from, count, show_repeat);
	}
	
	PDEBUG_DISP ( "Finished.\n" );
	return 0;
}

